.PHONY : all compile link clean rebuild
# 声明伪目标，避免与同名文件冲突。这些伪目标包括all、compile、link、clean和rebuild。

MODULES := common \
           module \
           main
# 定义模块列表，这些模块会被单独编译。

MKDIR := mkdir
RM := rm -fr
# 定义用于创建目录和删除文件/目录的命令。

CC := gcc
LFLAGS := 
# 定义C编译器为gcc，LFLAGS用于链接时的额外参数（当前为空）。

DIR_PROJECT := $(realpath .)
DIR_BUILD := build
DIR_BUILD_SUB := $(addprefix $(DIR_BUILD)/, $(MODULES))
MODULE_LIB := $(addsuffix .a, $(MODULES))
MODULE_LIB := $(addprefix $(DIR_BUILD)/, $(MODULE_LIB))
# 定义项目的根目录，构建目录，以及各模块的构建子目录。
# MODULE_LIB用于存储各模块生成的静态库文件名，并加上构建目录前缀。

APP := app.out
APP := $(addprefix $(DIR_BUILD)/, $(APP))
# 定义最终生成的应用程序文件名，并加上构建目录前缀。

all : compile $(APP)
	@echo "Success! Target ==> $(APP)"
# 默认目标all，先编译模块，再生成最终的应用程序，并输出成功信息。

compile : $(DIR_BUILD) $(DIR_BUILD_SUB)
	@echo "Begin to compile ..."
	@set -e; \
	for dir in $(MODULES); \
	do \
		cd $$dir && $(MAKE) all DEBUG:=$(DEBUG) && cd .. ; \
	done
	@echo "Compile Success!"
# 编译目标compile，首先创建必要的构建目录，然后遍历每个模块目录，执行`make all`命令来编译每个模块，并传递DEBUG变量。最后输出编译成功信息。

link $(APP) : $(MODULE_LIB)
	@echo "Begin to link ..."
	$(CC) -o $(APP) -Xlinker "-(" $^ -Xlinker "-)" $(LFLAGS)
	@echo "Link Success!"
# 链接目标link，依赖于所有模块的静态库。使用gcc进行链接，生成最终的应用程序，并输出链接成功信息。
# `-Xlinker "-(" $^ -Xlinker "-)"` 是为了确保静态库按顺序链接，防止符号丢失。

$(DIR_BUILD) $(DIR_BUILD_SUB) : 
	$(MKDIR) $@
# 目标：创建构建目录和各模块的子目录。

clean : 
	@echo "Begin to clean ..."
	$(RM) $(DIR_BUILD)
	@echo "Clean Success!"
# 清理目标clean，删除整个构建目录，输出清理成功信息。

rebuild : clean all
# 重建目标rebuild，先执行clean再执行all，即先清理再重新编译和链接。
